home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 06 - 1990 / 06.02 Feb 90 / Mouse Source / TrackRebuild.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-07-22  |  5.0 KB  |  186 lines  |  [TEXT/KAHL]

  1. /*                                        TrackRebuild.c                                        */
  2. /*
  3.  * Copyright © 1989 Martin Minow. All rights reserved.
  4.  *
  5.  * This routine is called whenever the contents of
  6.  * the TrackRecord text changes. It rebuilds the
  7.  * line start vector and repaints the display.
  8.  */  
  9. #include "TrackEdit.h"
  10. #define TR        (*tr)
  11. #define NIL        0L
  12. #define TR_SIZE(tr)    \
  13.     sizeof (TrackRecord) + (sizeof (DOT) * (*tr).nLines);
  14.  
  15. static TrackPtr    newline(TrackHandle, DOT);
  16.  
  17. /*
  18.  * _Track_rebuild(track_handle, start)
  19.  *
  20.  * _Track_rebuild() is called whenever the content of
  21.  * the TrackRecord text string changes.  It rebuilds
  22.  * the lineStarts vector and forces the text to be
  23.  * redrawn on the screen.  _Track_rebuild is the only
  24.  * routine that understands line breaks and such.
  25.  * Walk through the string to build a vector that locates
  26.  * the start of each line. There is always one extra entry
  27.  * so the number of characters in the last line can be
  28.  * computed.  The display window is the current port.
  29.  * Note that the word/line algorithm only notices
  30.  * whitespace.  The start parameter identifies the first
  31.  * character that has changed.
  32.  *
  33.  * Since _Track_rebuild temporarily unlocks the
  34.  * TrackRecord, it returns the current value of the
  35.  * relocked record.
  36.  */
  37. TrackPtr
  38. _Track_rebuild(track_handle, start)
  39. TrackHandle    track_handle;
  40. DOT                    start;
  41. {
  42.         register TrackPtr        tr;
  43.         register unsigned        c;
  44.         register DOT                index;
  45.         register DOT                line_break;    /* space here                */
  46.         register DOT                line_start;    /* -> start of line    */
  47.         register INTEGER        line_width;    /* Current width        */
  48.         LONGINT                            size;
  49.         LONGINT                            row;
  50.         LONGINT                            old_row, new_row;
  51.         Rect                                box;
  52.         
  53.         tr = *track_handle;
  54.         MoveHHi(TR.hText);                            /* Lock the text        */
  55.         HLock(TR.hText);                                /* record.                    */
  56.         if (start == 0) {
  57.             TR.nLines = 0;
  58.             index = 0;
  59.         }
  60.         else {
  61.             /*
  62.              * Start at the previous line since, if we delete
  63.              * the end of the first word on a line, it might
  64.              * fit on the previous line.
  65.              */
  66.             TR.nLines = _Track_row(tr, start);
  67.             if (TR.nLines > 0)
  68.                 --TR.nLines;
  69.             index = TR.lineStarts[TR.nLines];
  70.         }
  71.         /*
  72.          * Get the screen position *before* munging the lines.
  73.          */
  74.         old_row = _Track_row(tr, start);
  75.         tr = newline(track_handle, index);
  76.         line_start = index;
  77.         line_width = 0;
  78.         line_break = 0;
  79.         /*
  80.          * Each pass through this loop eats one character.
  81.          */
  82.         while (index < TR.textLength) {
  83.             c = (*TR.hText)[index++];            /* Grab the byte        */
  84.             if (c == '\r')
  85.                 goto do_newline;
  86.             line_width += CharWidth(c);
  87.             if (TR.crOnly < 0 || line_width <= TR.lineWidth) {
  88.                 /*
  89.                  * This byte fits.  If it's a word break, remember
  90.                  * its location for the end of line test.
  91.                  */
  92.                 if (_Track_is_white(tr, *TR.hText, index - 1))
  93.                     line_break = index;
  94.             }
  95.             else {
  96.                 /*
  97.                  * We're at the end of the line.  If we've seen
  98.                  * a word, break the line there.  Else, break
  99.                  * at the previous byte (if there is one on this
  100.                  * line,  if the first byte on the line doesn't
  101.                  * fit, stuff it in so we don't loop forever.
  102.                  */
  103.                 if (line_break != 0)
  104.                     index = line_break;            /* Break at word            */
  105.                 else if (index > (line_start + 1)) {
  106.                     --index;                                /* Rescan this one        */
  107.                 }
  108. do_newline:
  109.                 tr = newline(track_handle, index);
  110.                 line_start = index;
  111.                 line_width = 0;
  112.                 line_break = 0;
  113.             }
  114.         }                                                            /* Loop on characters    */
  115.         TR.lineStarts[TR.nLines] = TR.textLength;
  116.         HUnlock(TR.hText);
  117.         /*
  118.          * All of the line lengths have been set.  Adjust
  119.          * the TrackRecord size in case it's shrunk.
  120.          */
  121.         size = TR_SIZE(tr)
  122.         if (size > GetHandleSize(track_handle)) {
  123.             HUnlock(track_handle);
  124.             SetHandleSize(track_handle, size);
  125.             MoveHHi(track_handle);
  126.             HLock(track_handle);
  127.             tr = *track_handle;
  128.         }
  129.         /*
  130.          * Locate this row on the screen.  If it (or anything
  131.          * later on) will be visible, repaint as little
  132.          * as possible.  Note that we may have to repaint
  133.          * the row that the selection *was* on before we
  134.          * started messing with the lines.
  135.          */
  136.         new_row = _Track_row(tr, start);
  137.         if (new_row < old_row)
  138.             old_row = new_row;
  139.         row = _Track_row_pixel(tr, old_row) - TR.fontAscent;
  140.         box = TR.viewRect;
  141.         if (row <= (LONGINT) box.bottom) {
  142.             if (row > (LONGINT) box.top)
  143.                 box.top = row;
  144.             EraseRect(&box);
  145.             _Track_do_update(tr, &box);
  146.             ValidRect(&box);
  147.         }
  148.         return (tr);
  149. }
  150.  
  151.  
  152. /*
  153.  * newline()
  154.  * Called when a new line is ready: this sets the
  155.  * handle size and stores the index to the first
  156.  * character in this line.
  157.  */
  158. static TrackPtr
  159. newline(track_handle, index)
  160. TrackHandle    track_handle;
  161. DOT                    index;
  162. {
  163.         register TrackPtr    tr;
  164.         _Track_state            state;
  165.         LONGINT                        size;
  166.         
  167.         tr = *track_handle;
  168.         ++TR.nLines;
  169.         size = TR_SIZE(tr);
  170.         if (size > GetHandleSize(track_handle)) {
  171.             /*
  172.              * Reallocate the track handle to its proper size.
  173.              * You can allocate a chunk of lines here without
  174.              * problems.
  175.              */
  176.             HUnlock(track_handle);
  177.             SetHandleSize(track_handle, size);
  178.             MoveHHi(track_handle);
  179.             HLock(track_handle);
  180.             tr = *track_handle;
  181.         }
  182.         TR.lineStarts[TR.nLines - 1] = index;
  183.         return (tr);
  184. }
  185.  
  186.